import numpy as np
from DATA import DATA
np.random.seed(951105)

class ROAD(object):
    def __init__(self,id_, length_, speed_, channel_, from_, to_, isDuplex_):
        # **** statistic parameters ****#
        self.id_, self.length_, self.speed_, self.channel_, self.from_, self.to_, self.isDuplex_ = \
            id_, length_, speed_, channel_, from_, to_, isDuplex_
        self.carCapcity = self.channel_ * self.length_
        # **** dynamic parameters ****#
        # absolute bucket
        self.forwardBucket = {i: [None for j in range(self.channel_)] for i in range(self.length_)}
        # print("channel_",self.channel_,"self.length_",self.length_,"\nself.forwardBucket",self.forwardBucket)
        """        self.forwardBucket {0: [None, None, None, None], 
                    1: [None, None, None, None], 2: [None, None, None, None], 3: [None, None, None, None], 4: [None, None, None, None], 
                    5: [None, None, None, None], 6: [None, None, None, None], 7: [None,None, None, None], 8: [None, None, None, None], 9: [None, None, None, None]}
        """
        self.backwardBucket = {i: [None for j in range(self.channel_)] for i in
                               range(self.length_)} if self.isDuplex_ else None
        self.fx, self.fy, self.bx, self.by, self.forwardNum, self.backwardNum = [0], [0], [0], [0], [0], [0]
        self.forwardDone, self.backwardDone = [False], [False]
        # relative bucket
        self.provideBucket, self.receiveBucket = None, None
        self.px, self.py, self.provideNum, self.receiveNum = None, None, None, None
        self.provideDone = None
    #
    # determine relative bucket
    #
    def chooseAbsoluteBucket(self,crossId,pr):
        if crossId == self.from_ and pr == 'provide':
            return 'backward'
        elif crossId == self.from_ and pr == 'receive':
            return 'forward'
        elif crossId == self.to_ and pr == 'provide':
            return 'forward'
        elif crossId == self.to_ and pr == 'receive':
            return 'backward'
        else:
            print("Keywords mistake in CAR.chooseAbsoluteBucket()")
    def setBucket(self,crossId):
        bucket = self.chooseAbsoluteBucket(crossId, 'provide')
        if bucket == 'forward':
            self.provideBucket, self.px, self.py, self.provideDone, self.provideNum = \
                [self.forwardBucket, self.fx, self.fy, self.forwardDone, self.forwardNum]
            if self.isDuplex_:
                self.receiveBucket, self.receiveNum = \
                    self.backwardBucket, self.backwardNum
            else:
                self.receiveBucket, self.receiveNum = None, None
        else:
            self.receiveBucket, self.receiveNum = \
                self.forwardBucket, self.forwardNum
            if self.isDuplex_:
                self.provideBucket, self.px, self.py, self.provideDone, self.provideNum = \
                    self.backwardBucket, self.bx, self.by, self.backwardDone, self.backwardNum
            else:
                self.provideBucket, self.px, self.py, self.provideDone, self.provideNum = \
                    None, None, None, None, None
    #
    # stepInitial
    #
    def stepInit(self):
        # dynamic param initialization
        self.fx, self.fy, self.bx, self.by = [0], [0], [0], [0]
        self.forwardDone, self.backwardDone = [False], [False]
        self.provideBucket, self.receiveBucket = None, None
        self.px, self.py, self.provideNum, self.receiveNum = None, None, None, None
        self.provideDone = None
        
        """
        # car state initialization
        按照同一条道路上的车辆的优先级。来找到优先级最高的那辆车
        forwardBucket 【i】【j】存储的车辆的ID i是道路的长度 J十第几条到
        
        """
        
        for i in range(self.length_):#
            for j in range(self.channel_):
                if self.forwardBucket[i][j] is not None:
                    car = DATA.CARDICT[self.forwardBucket[i][j]]
                    car.updateDynamic(state=1)
                if self.isDuplex_:
                    if self.backwardBucket[i][j] is not None:
                        car = DATA.CARDICT[self.backwardBucket[i][j]]
                        car.updateDynamic(state=1)
        """
        first step
        移动可以行走的车辆
        """
        for channel in range(self.channel_):
            self.moveInChannel(self.forwardBucket, channel)
            if self.isDuplex_:
                self.moveInChannel(self.backwardBucket, channel)
    #
    # function for bucket action
    #
    def moveInChannel(self,bucket,channel):
        """
         car state: 0,1,2,3 in 在车库,等待,完成一步行走,行程结束
         set guard
        forwardBucket 【i】【j】存储的车辆的ID i是道路的长度 j 是第几条道路
        
        """
        previousCar, previousState = -1, 1
        ##前方的车辆的在道路的位置和状态
        

        for i in range(self.length_):
            if bucket[i][channel] is not None:
                car = DATA.CARDICT[bucket[i][channel]]
                v = min(car.__speed__(),self.speed_) #速速度设置为车速的道路速度的最小值
                if car.__state__() == 2: #完成一步行走
                    previousCar, previousState = i, 2 # i 表示在道路的位置
                    continue
                elif i - v > previousCar:#如果车辆可以行走，并且不会到达十字路口
                    bucket[i - v][channel] = bucket[i][channel]
                    bucket[i][channel] = None
                    previousCar, previousState = i - v, 2
                    car.updateDynamic(state=2, x=previousCar)
                elif previousState == 2: #如果前方车辆已经完成一步行走，车辆可以行走，并且前方还有位置
                    if previousCar + 1 != i:#如果前方车辆与这个车辆之间还有位置
                        bucket[previousCar + 1][channel] = bucket[i][channel] #将车辆行走到相应的位置
                        bucket[i][channel] = None
                    previousCar, previousState = previousCar + 1, 2
                    car.updateDynamic(state=2, x=previousCar)
                else:
                    previousCar, previousState = i, 1
    def findCar(self,st,end,channel,bucket):
        # find car backward
        for i in range(end, st, -1):
            if bucket[i][channel] is not None:
                return i
        return -1
    #
    # provide car
    #
    def firstPriorityCar(self):
        if self.provideBucket is None:#如果没有驶入的车辆
            print("Please do CAR.setBucket() first!")
        while self.px[0] <  self.length_:
            carId = self.provideBucket[self.px[0]][self.py[0]]
            if carId is not None and DATA.CARDICT[carId].__state__() != 2:
                car = DATA.CARDICT[carId]
                left = min(car.__speed__(),self.__speed__())
                # speed enough and no front car
                if left > self.px[0] and self.findCar(-1, self.px[0] - 1, self.py[0], self.provideBucket) == -1:
                    return self.provideBucket[self.px[0]][self.py[0]]
            if self.py[0] == self.channel_ - 1:
                self.px[0], self.py[0] = self.px[0] + 1, 0
            else:
                self.py[0] += 1
        self.provideDone[0] = True
        return -1

    def firstPriorityCarAct(self,action):
        if self.provideBucket is None:
            print("Please do CAR.setBucket() first!")
        if action == 0:
            self.provideBucket[self.px[0]][self.py[0]] = None
            self.provideNum[0] -= 1
        elif action == 1:
            carId = self.provideBucket[self.px[0]][self.py[0]]
            self.provideBucket[self.px[0]][self.py[0]] = None
            self.provideBucket[0][self.py[0]] = carId
        self.moveInChannel(self.provideBucket, self.py[0])
    #
    # receive car
    #
    def receiveCar(self,carId):
        if self.receiveBucket is None:
            print("Please do CAR.setBucket() first!")
        car = DATA.CARDICT[carId]
        leftX = min(self.speed_, car.__speed__()) - car.__x__()
        nextCrossId = self.from_ if car.__nextCrossId__() != self.from_ else self.to_
        if leftX <= 0:
            car.updateDynamic(state=2,x=0)
            return 1
        #find front car
        for i in range(self.channel_):
            frontCarLoc = self.findCar(self.length_ - leftX - 1, self.length_ - 1, i, self.receiveBucket)
            # if no front car
            if frontCarLoc == -1:
                self.receiveBucket[self.length_ - leftX][i] = carId
                self.receiveNum[0] += 1
                car.updateDynamic(state=2, x=self.length_ - leftX, y=i, presentRoad=self.id_, roadSpeed=self.speed_,
                           nextCrossId=nextCrossId)
                return 0
            frontCar = DATA.CARDICT[self.receiveBucket[frontCarLoc][i]]
            # if frontCar.state == waiting
            if frontCar.__state__() == 1:
                return 2
            # if frontCar.state == finish and frontCar.x != road.__length__()-1
            elif frontCarLoc != self.length_ - 1:
                self.receiveBucket[frontCarLoc + 1][i] = carId
                self.receiveNum[0] += 1
                car.updateDynamic(state=2, x=frontCarLoc + 1, y=i, presentRoad=self.id_, roadSpeed=self.speed_,
                           nextCrossId=nextCrossId)
                return 0
            # if frontCar.state == finish and frontCar.x == road.__length__()-1
            else:
                continue
        # if road is full
        car.updateDynamic(state=2, x=0)
        return 1
    #
    # show statistic parameters
    #
    def __id__(self):
        return self.id_
    def __length__(self):
        return self.length_
    def __speed__(self):
        return self.speed_
    def __channel__(self):
        return self.channel_
    def __from__(self):
        return self.from_
    def __to__(self):
        return self.to_
    def __isDuplex__(self):
        return self.isDuplex_
    def __carCapcity__(self):
        return self.carCapcity
    #
    # show statistic parameters
    #
    def __forwardBucket__(self):
        return self.forwardBucket
    def __backwardBucket__(self):
        return self.backwardBucket
    def __fx__(self):
        return self.fx[0]
    def __fy__(self):
        return self.fy[0]
    def __bx__(self):
        return self.bx[0]
    def __by__(self):
        return self.by[0]
    def __forwardNum__(self):
        return self.forwardNum[0]
    def __backwardNum__(self):
        return self.backwardNum[0]
    def __forwardDone__(self):
        return self.forwardDone[0]
    def __backwardDone__(self):
        return self.backwardDone[0]
    def __provideBucket__(self):
        return self.provideBucket
    def __receiveBucket__(self):
        return self.receiveBucket
    def __px__(self):
        return self.px[0]
    def __py__(self):
        return self.py[0]
    def __provideNum__(self):
        return self.provideNum[0]
    def __receiveNum__(self):
        return self.receiveNum[0]
    def __provideDone__(self):
        return self.provideDone[0]